package com.dong.framework;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class LubanApplicationcContext {
    private Class appConfig;
    private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
    private Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();
    private List<BeanPostProcessor> beanPostProcessorList=new ArrayList<BeanPostProcessor>();


    public LubanApplicationcContext(Class appConfig) {
        this.appConfig = appConfig;

        //扫描类注解--->得到BeanDefinition
        scan(appConfig);

        //创建Bean（非懒加载的单例bean）
        instanceNonLazySingletonBean();

    }

    //实例化非懒加载的单例bean
    private void instanceNonLazySingletonBean() {
        for (String beanName : beanDefinitionMap.keySet()) {
            BeanDefinition bd = beanDefinitionMap.get(beanName);
            if (!bd.isLazy() && "singleton".equals(bd.getScope())) {
                addSingletonPool(beanName, bd);
            }
        }
    }

    //加入到单例池
    private Object addSingletonPool(String beanName, BeanDefinition bd) {
            Object bean = creatBean(beanName, bd);
            singletonObjects.put(beanName, bean);
            return bean;
    }


    //创建Bean
    public Object creatBean(String beanName, BeanDefinition bd) {
        Class beanClass = bd.getBeanClass();
        try {
            //实例化一个bean
            Object instance = beanClass.getDeclaredConstructor().newInstance();

            //依赖注入(根据类型注入)  bean的生命周期
          for(Field field : beanClass.getDeclaredFields()) {
              //属性上是否有@Autowired注解
                if(field.isAnnotationPresent(Autowired.class)){
                    Class fieldType = field.getType();
                    field.setAccessible(true);
                    for (String bn : beanDefinitionMap.keySet()) {
                        BeanDefinition definition = beanDefinitionMap.get(bn);
                        if(fieldType.equals(definition.getBeanClass())){
                            Object bean = getBean(bn);
                            field.set(instance,bean);
                        }
                    }
                }
            }

          //BeanPostProcessor后置处理器
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance=beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
            }

            return instance ;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    //获取Bean
    public Object getBean(String beanname) {
        BeanDefinition bd = beanDefinitionMap.get(beanname);
        //当bd不为空,bd的Scope为单例时,单例池包含bean就可以直接拿.
        if (bd != null) {
            if ("singleton".equals(bd.getScope())) {
                //单例池中是否含有bean
                if (singletonObjects.containsKey(beanname)) {
                    return singletonObjects.get(beanname);
                } else {
                    return addSingletonPool(beanname, bd);
                }
            }
        }
        return creatBean(beanname, bd);
    }


    //扫描类上的注解
    private void scan(Class appConfig) {
        //判断配置类上面是否有ComponentScan注解
        if (appConfig.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan annotation = (ComponentScan) appConfig.getAnnotation(ComponentScan.class);
            String path = annotation.value();
            path = path.replace(".", "/");
            System.out.println(path);
            URL resource = this.getClass().getClassLoader().getResource(path);
            //把URL变成一个文件
            File file = new File(resource.getFile());
            System.out.println("文件：" + file);
            scanFile(file);
        }
    }

    private void scanFile(File file) {
        String projectPath = this.getClass().getResource("/").getPath();
        //listFiles()方法返回某个目录下所有文件和目录的绝对路径
        // 遍历文件下的文件或者目录
        for (File f : file.listFiles()) {
            //递归找到要扫描的文件
            if (!f.isDirectory()) {
                //获取文件的相对路径
                String fileName = f.getAbsolutePath();
                System.out.println(fileName);
                //判断文件是否以.class结尾
                if (fileName.endsWith(".class")) {
                    String str = fileName.replace(new File(projectPath)+"\\", "");
                    str = str.substring(0, str.lastIndexOf("."));
                    str = str.replace("\\", ".");
                    System.out.println(str);
                    try {
                        //加载类
                        Class<?> clazz = this.getClass().getClassLoader().loadClass(str);
                        System.out.println(clazz);

                        //判断类上是否有Component注解
                        if (clazz.isAnnotationPresent(Component.class)||
                                clazz.isAnnotationPresent(Service.class)||
                                clazz.isAnnotationPresent(Repository.class)||
                                clazz.isAnnotationPresent(Controller.class)) {
                            String beanName=null;

                            //扫描到有Component注解就要生成一个bd
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setBeanClass(clazz);

                            //获取Component注解的Value
                            if(clazz.isAnnotationPresent(Component.class)) {
                                Component component = clazz.getAnnotation(Component.class);
                                beanName = component.value();
                            }

                            if(clazz.isAnnotationPresent(Controller.class)) {
                                Controller controller = clazz.getAnnotation(Controller.class);
                                beanName = controller.value();
                            }

                            //获取Service注解的Value
                            if(clazz.isAnnotationPresent(Service.class)){
                                Service service = clazz.getAnnotation(Service.class);
                                beanName = service.value();
                            }

                            if(clazz.isAnnotationPresent(Repository.class)){
                                Repository repository = clazz.getAnnotation(Repository.class);
                                beanName = repository.value();
                            }

                            //如果类中的Component没有标明名字的话,直接转换为类名的首字母小写.
                            if ("".equals(beanName) || beanName == null) {
                                beanName = switcher(clazz.getSimpleName());
                            }
                            //类是否有Lazy注解
                            if (clazz.isAnnotationPresent(Lazy.class)) {
                                beanDefinition.setLazy(true);
                            }

                            //类上是否有Scope注解
                            if (clazz.isAnnotationPresent(Scope.class)) {
                                Scope scope = clazz.getAnnotation(Scope.class);
                                beanDefinition.setScope(scope.value());
                            } else {
                                beanDefinition.setScope("singleton");
                            }

                            //clazz是否实现了BeanPostProcessor这个接口
                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                beanPostProcessorList.add((BeanPostProcessor) clazz.getDeclaredConstructor().newInstance());
                            }
                            beanDefinitionMap.put(beanName, beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }else {
                scanFile(f);
            }
        }
    }

    //把字符串的第一个字母变为小写
    public  String switcher(String str){
        return new StringBuffer().append(Character.toLowerCase(str.charAt(0))).append(str.substring(1)).toString();
    }
}
